package com.olt.server.oltCenter.oltClass;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.olt.dao.oltCenter.IClassStudent;
import com.olt.dao.oltCenter.IOltClassDao;
import com.olt.domain.oltCenter.ClassStudent;
import com.olt.domain.oltCenter.OltClass;
import com.olt.server.oltCenter.oltClass.dto.CreatOltClassInput;
import com.olt.server.oltCenter.oltClass.dto.GetOltClassInput;
import com.olt.server.oltCenter.oltStudentServer.dto.DeleteStudentInput;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import util.MapperUtil;

import javax.persistence.criteria.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Transactional(rollbackForClassName="RuntimeException")
public class OltClassServer {
    @Autowired
    IOltClassDao iOltClassDao;
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    @Autowired
    IClassStudent classStudent;

    public Page<OltClass> getOltClass(GetOltClassInput input) {

        var spec = new Specification<OltClass>() {
            @Override
            public Predicate toPredicate(Root<OltClass> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates=new ArrayList<>();
                if(StrUtil.isNotEmpty(input.getKey())) {
                    predicates.add(
                            cb.like(root.get("className"), input.getKey())
                    );
                }
                if(input.getCanSelect()!=null){
                    predicates.add(
                            cb.equal(root.get("canSelect"),input.getCanSelect())
                    );
                }
                if(input.getHavValidity()!=null){
                    predicates.add(
                            cb.equal(root.get("havValidity"),input.getHavValidity())
                    );
                }
                if(input.getIsOpen()!=null){
                    predicates.add(
                            cb.equal(root.get("isOpen"),input.getIsOpen())
                    );
                }
                predicates.add(
                        cb.greaterThanOrEqualTo(root.get("creatTime"),input.getBegin())
                );
                predicates.add(
                        cb.lessThan(root.get("creatTime"),input.getEnd())
                );
                predicates.add(
                        cb.equal(root.get("createUser"),input.getMe())
                );
                var predicateArray=new Predicate[predicates.size()];
                return query.
                        where(predicates.toArray(predicateArray)).
                        orderBy(cb.desc(root.get("creatTime"))).
                        getRestriction();
            }
        };
        var page= PageRequest.of(input.getCurrentPage(), input.getSize());
        return iOltClassDao.findAll(spec,page);
    }

    public void saveOltClass(CreatOltClassInput input,Long userId) throws Exception{
        OltClass oltClass=new OltClass();
        MapperUtil.MapperClass(oltClass,input);
        if(input.getClassId()==null) {
            oltClass.setClassId(IdUtil.simpleUUID());
            oltClass.setCreateUser(userId);
            oltClass.setCreatTime(new Date());
        }
        else {
            var olt=iOltClassDao.getOne(input.getClassId());
            if(!Objects.equals(olt.getCreateUser(), userId)){
                throw new Exception("你不是创建者无法修改");
            }
            oltClass.setCreatTime(olt.getCreatTime());

        }
        if(input.getHavValidity()) {
            oltClass.setValidity(input.getValidity());
        }
        else {
            oltClass.setValidity(null);
        }
        iOltClassDao.save(oltClass);

    }


    public CreatOltClassInput getClassForEdit(String uuid){
        var res=  iOltClassDao.getOne(uuid);
        var out=new CreatOltClassInput();
        out.setCanSelect(res.getCanSelect());
        out.setClassId(res.getClassId());
        out.setValidity(res.getValidity());
        out.setClassName(res.getClassName());
        out.setHavValidity(res.getHavValidity());
        out.setIsOpen(res.getIsOpen());
        out.setImgUrl(res.getImgUrl());
        return out;
    }

    public String createSessionJoinKey(String classId,Long userId){
        try {
            var oltClass = iOltClassDao.getOne(classId);
            if (!Objects.equals(oltClass.getCreateUser(), userId))
                return null;
            var sessionKey = UUID.randomUUID().toString();
            Map<String, String> session = new HashMap<>();
            session.put("name", oltClass.getClassName());
            session.put("key", sessionKey);
            redisTemplate.opsForValue().set(classId.toString(), JSON.toJSONString(session), 1, TimeUnit.HOURS);
            return sessionKey;
        }
        catch (Exception e){
            return null;
        }
    }
    public String getJoinClass(String classId,String key,Long userId)throws Exception{
        var str=redisTemplate.opsForValue().get(classId.toString());
        if(str==null){
            throw  new Exception("未找到班级");
        }
        if(classStudent.findByClassIdAndUserId(classId,userId)!=null) {
            return null;
        }
        var r= JSON.parseObject(str,HashMap.class);
        if(!key.equals(r.get("key").toString())){
            throw  new Exception("session错误");
        }
        return  str;
    }

    public String joinClass(String classId,String key,Long userId)throws Exception{
        var value=getJoinClass(classId,key,userId);
        if(value!=null){
            var classAndStudent=new ClassStudent();
            classAndStudent.setClassStudentId(IdUtil.simpleUUID());
            classAndStudent.setClassId(classId);
            classAndStudent.setUserId(userId);
            classAndStudent.setJoinTime(new Date());
            classStudent.save(classAndStudent);

        }
        return "OK";

    }


    public Boolean deleteStudentFormClass(DeleteStudentInput input){
        classStudent.deleteAllByClassIdAndUserIdIn(input.getClassId(),input.getUserId());
        return true;
    }


    public void deleteClass(String[] uuids){
        iOltClassDao.deleteByClassIdIn(Arrays.asList(uuids.clone()));
    }


    public Page<OltClass> getClassMyJoin(GetOltClassInput input,Long userId){
        var page= PageRequest.of(input.getCurrentPage(), input.getSize());
        return  iOltClassDao.getClassByJoin(input.getKey(),userId,input.getBegin(),input.getEnd(),page);

    }


}
